package dm.ast;

import dm.ast.model.gen.AggregateGen;
import test.envset.GlobalState;
import test.utility.Randomly;

import java.util.ArrayList;
import java.util.List;

/**
 * select语句中的查询列
 */
public class DmSelectElements extends DmASTNode{
    public List<DmExpression> elements = null;

    public int elements_size = 0;

    public boolean starFlag = false;  //starFlag True means select * 目前仅在exists中使用select *

    public DmSelectElements() {
        elements = new ArrayList<DmExpression>();
    }

    public void addElement(DmExpression element){
        elements.add(element);
        elements_size++;
    }

    //指定次序添加查询列
    public void addElement(DmExpression element , int i){
        elements.set(i , element);
    }

    //根据索引返回查询列中的某个查询列
    public DmExpression getElement(int i){
        if(i < elements_size && i >= 0){
            return elements.get(i);
        }else {
            return null;
        }
    }

    public int getSelectElementsSize(){
        return elements_size;
    }



    @Override
    public void fill(GlobalState globalState) {
        if(!isCompleted){
            if(!starFlag){
                for (int i = 0; i < elements_size; i++) {
                    elements.get(i).fill(globalState);
                }
            }else {
                //select * 需要把查询表的所有列都加入查询列中
                elements.clear();
                elements_size = 0;
                List<DmTableSource> fromSel = globalState.getCurrentFrom();
                for(DmTableSource from : fromSel){
                    List<DmColumn> cols = from.cols;
                    for (DmColumn col : cols) {
                        elements.add(col);
                        elements_size++;
                    }
                }
            }
            isCompleted = true;
        }
    }

    @Override
    public void setWidt() {
        if(starFlag){
            wid_t = 1;
            return;
        }
        wid_t = 0;
        for (int i = 0; i < elements_size; i++) {
            elements.get(i).setWidt();
            wid_t += elements.get(i).getWidt();
        }
    }

    @Override
    public void setDept() {
        if(starFlag){
            dep_t = 1;
            return;
        }
        int tmpMaxwid_t = 1;
        for (int i = 0; i < elements_size; i++) {
            elements.get(i).setDept();
            if(elements.get(i).dep_t > tmpMaxwid_t){
                tmpMaxwid_t = elements.get(i).getDept();
            }
        }
        dep_t = tmpMaxwid_t;
    }

    @Override
    public DmDataType getExpressionType() {
        if(elements_size == 1){
            return elements.get(0).getExpressionType();
        }else {
            return null;
        }
    }

    public String toSql(){
        if(elements_size == 0){
            return " " + this.getClass().getSimpleName() + getSqlTarget();
        }else {
            if(starFlag){
                return "*";
            }else {
                StringBuilder sql = new StringBuilder();
                sql.append(elements.get(0).toSelectElementSql());
                for (int i = 1; i < elements.size(); i++) {
                    sql.append(", " + elements.get(i).toSelectElementSql());
                }

                return sql.toString();
            }
        }
    }

    //需要处理非分组项的查询列，增加集函数
    //参数为group分组项的数目，它同时表示前多少个列是分组项，不需要处理
    public void dealGroupy(int groups){
        if(groups >= elements_size){   //表示所有查询列都是分组列，此时不需要额外操作
            return;
        }
        List<DmExpression> tmp = new ArrayList<DmExpression>();
        List<DmExpression> groupings = new ArrayList<DmExpression>();
        int i = 0;
        int j = 0;
        //找到所有分组项的查询列并跳过，非分组项需要放入临时列表中处理
        //找到所有分组项后，剩余的查询列都是非分组项，需要放入临时列表中处理
        for (i = 0 , j = 0; i < elements_size && j < groups; i++) {
            DmExpression ele = elements.get(i);
            if(ele.getDept() > 1){   //查询列为子查询，肯定不是分组项
                tmp.add(getElement(i));
                elements.set(i , null);
            }else {
                //小概率生成GROUPING函数
                if(Randomly.getBooleanWithSmallProbability()){
                    groupings.add(AggregateGen.getGrouping(ele));
                }
                j++;
            }
        }

        for(; i < elements_size ; i++){
            tmp.add(getElement(i));
            elements.set(i , null);
        }

        for(i = 0 , j = 0; i < tmp.size(); i++){
            DmExpression exp = tmp.get(i);
            for(; j < elements_size; j++){
                if(elements.get(j) == null){
                    break;
                }
            }

            addElement(AggregateGen.getRandAggregate(exp.reType , exp) , j);
        }

        for(DmExpression grouping : groupings){
            addElement(grouping);
        }
    }

    //处理sql错误
    // -4097|单行子查询返回多行
    public void fixErr4097(){
        if(!starFlag){
            for (int i = 0; i < elements_size; i++) {
                DmExpression.fixErr4097Low(elements.get(i));
            }
        }
    }
}
